﻿using System;

using SharpGL.Media3D;

namespace SharpGL.SceneGraph.Helpers
{
    class TransformationHelper
    {
        /// <summary>
        /// Create translate transformation matrix.
        /// </summary>
        /// <param name="translateX">The x axial displacement.</param>
        /// <param name="translateY">The y axial displacement.</param>
        /// <param name="translateZ">The z axial displacement.</param>
        /// <returns>The transformation matrix.</returns>
        public static Matrix TranslateMatrix(double translateX, double translateY, double translateZ)
        {
            Matrix mat = new Matrix(4, 4);

            mat.SetIdentity();
            mat[0, 3] = translateX;
            mat[1, 3] = translateY;
            mat[2, 3] = translateZ;

            return mat;
        }

        /// <summary>
        /// Create scale transformation matrix.
        /// </summary>
        /// <param name="scaleX">The x axial scale.</param>
        /// <param name="scaleY">The y axial scale.</param>
        /// <param name="scaleZ">The z axial scale.</param>
        /// <returns>The transformation matrix.</returns>
        public static Matrix ScaleMatrix(double scaleX, double scaleY, double scaleZ)
        {
            Matrix mat = new Matrix(4, 4);

            mat.SetIdentity();
            mat[0, 0] = scaleX;
            mat[1, 1] = scaleY;
            mat[2, 2] = scaleZ;

            return mat;
        }

        /// <summary>
        /// Create rotation transformation matrix.
        /// </summary>
        /// <param name="angle">The angle of rotation (in degrees).</param>
        /// <param name="x">The x of rotation axis.</param>
        /// <param name="y">The y of rotation axis.</param>
        /// <param name="z">The z of rotation axis.</param>
        /// <returns>The transformation matrix.</returns>
        public static Matrix RotateMatrix(double angle, double x, double y, double z)
        {
            Matrix mat = new Matrix(4, 4);
            double sin, cos;
            double vectorLength;

            angle *= Math.PI / 180.0;

            vectorLength = Math.Sqrt(x * x + y * y + z * z);
            if (vectorLength != 0)
            {
                x /= vectorLength;
                y /= vectorLength;
                z /= vectorLength;
            }

            sin = Math.Sin(angle);
            cos = Math.Cos(angle);

            mat.SetIdentity();

            mat[0, 0] = cos + (1 - cos) * x * x;
            mat[0, 1] = (1 - cos) * x * y - sin * z;
            mat[0, 2] = (1 - cos) * x * z + sin * y;

            mat[1, 0] = (1 - cos) * y * x + sin * z;
            mat[1, 1] = cos + (1 - cos) * y * y;
            mat[1, 2] = (1 - cos) * y * z - sin * x;

            mat[2, 0] = (1 - cos) * z * x - sin * y;
            mat[2, 1] = (1 - cos) * z * y + sin * x;
            mat[2, 2] = cos + (1 - cos) * z * z;

            return mat;
        }

        /// <summary>
        /// Create rotation transformation matrix around x axis.
        /// </summary>
        /// <param name="angle">The angle of rotation (in degrees).</param>
        /// <returns>The transformation matrix.</returns>
        public static Matrix RotateXMatrix(double angle)
        {
            Matrix mat = new Matrix(4, 4);
            double sin, cos;

            angle *= Math.PI / 180.0;
            sin = Math.Sin(angle);
            cos = Math.Cos(angle);

            mat.SetIdentity();
            mat[1, 1] = cos;
            mat[1, 2] = -sin;
            mat[2, 1] = sin;
            mat[2, 2] = cos;

            return mat;
        }

        /// <summary>
        /// Create rotation transformation matrix around y axis.
        /// </summary>
        /// <param name="angle">The angle of rotation (in degrees).</param>
        /// <returns>The transformation matrix.</returns>
        public static Matrix RotateYMatrix(double angle)
        {
            Matrix mat = new Matrix(4, 4);
            double sin, cos;

            angle *= Math.PI / 180.0;
            sin = Math.Sin(angle);
            cos = Math.Cos(angle);

            mat.SetIdentity();
            mat[0, 0] = cos;
            mat[0, 2] = sin;
            mat[2, 0] = -sin;
            mat[2, 2] = cos;

            return mat;
        }

        /// <summary>
        /// Create rotation transformation matrix around z axis.
        /// </summary>
        /// <param name="angle">The angle of rotation (in degrees).</param>
        /// <returns>The transformation matrix.</returns>
        public static Matrix RotateZMatrix(double angle)
        {
            Matrix mat = new Matrix(4, 4);
            double sin, cos;

            angle *= Math.PI / 180.0;
            sin = Math.Sin(angle);
            cos = Math.Cos(angle);

            mat.SetIdentity();
            mat[0, 0] = cos;
            mat[0, 1] = -sin;
            mat[1, 0] = sin;
            mat[1, 1] = cos;

            return mat;
        }
    }
}
